﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;

namespace TLD_Vision
{
    [StructLayout(LayoutKind.Explicit)]
    public unsafe struct PixelData
    {
        [FieldOffset(0)]
        public uint ui;
        [FieldOffset(0)]
        public fixed byte bytes[4];

        [FieldOffset(0)]
        public byte b;
        [FieldOffset(1)]
        public byte g;
        [FieldOffset(2)]
        public byte r;
        [FieldOffset(3)]
        public byte a;
    }
    
    public class ImageData
    {
        public PixelData[] Data { get; private set; }
        public int Width { get; private set; }
        public int Height { get; private set; }

        public PixelData this[int index]
        {
            get { return Data[index]; }
            set { Data[index] = value; }
        }

        public PixelData this[int x, int y]
        {
            get { return Data[GetArrayIndex(x, y)]; }
            set { Data[GetArrayIndex(x, y)] = value; }
        }

        public ImageData(int height, int width)
        {
            Height = height;
            Width = width;
            Data = new PixelData[height * width];
        }

        public int GetArrayIndex(int x, int y)
        {
            return y * Width + x;
        }
        
        public PixelData GetPixel(int x, int y) 
        {
            return Data[GetArrayIndex(x,y)];
        }

        public void SetPixel(int x, int y, uint argb)
        {
            Data[GetArrayIndex(x,y)].ui = argb;
        }

        public void SetPixel(int x, int y, byte a, byte r, byte g, byte b)
        {
            int index = GetArrayIndex(x, y);
            Data[index].r = r;
            Data[index].g = g;
            Data[index].b = b;
            Data[index].a = a;
        }

        public void SetPixel(int x, int y, PixelData data) {
            Data[GetArrayIndex(x,y)] = data;
        }

        public Image ToImage()
        {
            Image img = new Image(Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            IntPtr dest = img.GetDataPointer();
            IntPtr src = Marshal.UnsafeAddrOfPinnedArrayElement(Data, 0);
            int numPixels = Width * Height;

            unsafe
            {
                try
                {
                    int numBytes = numPixels * 4;
                    memcpy(dest, src, new UIntPtr((uint)numBytes));
                }
                catch (EntryPointNotFoundException)
                {

                    int* srcPtr = (int*)Marshal.UnsafeAddrOfPinnedArrayElement(Data, 0);
                    int* dstPtr = (int*)dest;
                    for (int i = 0; i < numPixels; ++i)
                    {
                        dstPtr[i] = srcPtr[i];
                    }
                }
            }

            img.Unlock();

            return img;
        }

        public ImageData Clone()
        {
            ImageData clone = new ImageData(Height, Width);
            Data.CopyTo(clone.Data, 0);
            return clone;
        }

        [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
        public static extern IntPtr memcpy(IntPtr dest, IntPtr src, UIntPtr count);
    }
}
